package showtime.framework.utils
{
	/**
	 * @project 寻找红狼
	 * @date 2011-6-21
	 * @author 绿豆蛙
	 * 
	 */
	public final class DateUtility
	{
		public static const MONTHS_PER_YEAR:int = 12;
		public static const DAYS_PER_WEEK:int = 7;
		public static const HOURS_PER_DAY:int = 24;
		public static const MINUTES_PER_HOUR:int = 60;
		public static const SECONDS_PER_MINUTE:int = 60;
		
		public static const MILLIS_PER_SECOND:int = 1000;
		public static const MILLIS_PER_MINUTE:int = SECONDS_PER_MINUTE * MILLIS_PER_SECOND;
		public static const MILLIS_PER_HOUR:int = MINUTES_PER_HOUR * MILLIS_PER_MINUTE;
		public static const MILLIS_PER_DAY:int = HOURS_PER_DAY * MILLIS_PER_HOUR;
		
		private static const NOT_NULL_ASSERTION_MESSAGE:String = "NOT_NULL_ASSERTION_MESSAGE";
		private static const GMT_TIMEZONE_STRING:String = "GET_TIMEZONE_STRING";
		
		public function DateUtility()
		{
		}
		
		/**
		 * Comparion Functions.
		 *  
		 * @param date1
		 * @param date2
		 * @return 
		 * 
		 */		
		static public function isSameDay(date1:Date, date2:Date):Boolean
		{
			Assert.notNull(date1, NOT_NULL_ASSERTION_MESSAGE);
			Assert.notNull(date2, NOT_NULL_ASSERTION_MESSAGE);
			
			var result:Boolean = false;
			
			if (date1.getFullYear() == date2.getFullYear() && date1.getMonth() == date2.getMonth() && date1.getDate() == date2.getDate())
			{
				return true;
			}			
			return result;
		}
		
		/**
		 * HH:mm:SS 格式字符串。注意该方法会存在逻辑问题。
		 *  
		 * @param time
		 * @return 
		 * 
		 */		
		static public function formToTimeString(seconds:int):String
		{	
			return String("0" + Math.floor(seconds / 3600)).substr(-2) + ":" + String("0" + Math.floor(seconds / 60) % 60).substr(-2) + ":" + String("0" + Math.floor(seconds % 60)).substr(-2);
		}
		
		static public function addYears(date:Date, years:Number):Date 
		{
			return addMonths(date, years * MONTHS_PER_YEAR);
		}
		
		static public function addMonths(date:Date, months:Number):Date
		{
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			
			var result:Date = new Date(date.getTime());
			result.setMonth(date.month + months);
			result = handleShorterMonth(date, result);
			return result;
		}
		
		
		static public function addWeeks(date:Date, weeks:int):Date
		{
			return addDays(date, weeks * DAYS_PER_WEEK);
		}
		
		static public function addDays(date:Date, days:int):Date
		{
			var result:Date = add(date, MILLIS_PER_DAY, days);
			return handleDaylightSavingsTime(date, result);
		}
		
		static public function addHours(date:Date, hours:int):Date
		{
			return add(date, MILLIS_PER_HOUR, hours);
		}
		
		static public function addMinutes(date:Date, minutes:int):Date
		{
			return add(date, MILLIS_PER_MINUTE, minutes);
			
		}
		static public function addSeconds(date:Date, seconds:int):Date
		{
			return add(date, MILLIS_PER_SECOND, seconds);
		}
		
		static public function addMilliseconds(date:Date, milliseconds:int):Date
		{
			return add(date, 1, milliseconds);
		}
		
		static public function add(date:Date, multiplier:int, num:int):Date
		{
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			var resultTime:Number = date.getTime() + multiplier * num;
			
			return new Date(resultTime);
		}
		
		//////////////////////////
		//		Set functions.
		/////////////////////////
		static public function setYear(date:Date, year:int):Date
		{
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			var result:Date = new Date(year, date.month, date.date, date.hours, date.minutes, date.seconds, date.milliseconds);
			return handleShorterMonth(date, result);
		}
		
		static public function setMonth(date:Date, month:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			var result:Date = new Date(date.fullYear, month, date.date, date.hours, date.minutes, date.seconds, date.milliseconds);
			return handleShorterMonth(date, result);
		}
		
		static public function setDay(date:Date, day:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return new Date(date.fullYear, date.month, day, date.hours, date.minutes, date.seconds, date.milliseconds);
		}
		
		static public function setHours(date:Date, hour:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return new Date(date.fullYear, date.month, date.date, hour, date.minutes, date.seconds, date.milliseconds);
		}
		
		static public function setMinutes(date:Date, minute:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return new Date(date.fullYear, date.month, date.date, date.hours, minute, date.seconds, date.milliseconds);
		}
		
		static public function setSeconds(date:Date, second:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return new Date(date.fullYear, date.month, date.date, date.hours, date.minutes, second, date.milliseconds);
		}
		
		static public function setMilliseconds(date:Date, millisecond:int):Date {
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return new Date(date.fullYear, date.month, date.date, date.hours, date.minutes, date.seconds, millisecond);
		}
		
		////////////////////////////
		//		Misc Functions.
		////////////////////////////
		static public function getLocalTimeZoneCode():String
		{
			var dateString:String = new Date().toString();
			var startIndex:int = dateString.indexOf(GMT_TIMEZONE_STRING);
			var endIndex:int=dateString.indexOf(" ", startIndex);
			
			return dateString.substring(startIndex, endIndex);
		}
		
		static public function isLeapYear(date:Date):Boolean
		{
			Assert.notNull(date, NOT_NULL_ASSERTION_MESSAGE);
			return (date.fullYear % 400 == 0) || ((date.fullYear % 4 == 0) && (date.fullYear % 100 != 0));
		}
		
		static public function getYesterday():Date
		{
			var result:Date = new Date();
			result.setDate(result.getDate() - 1);
			return result;
		}
		
		static public function getTomorrow():Date 
		{
			var result:Date = new Date();
			result.setDate(result.getDate() + 1);
			return result;
		}
		
		////////////////////////////
		//		Helpers.
		////////////////////////////
		private static function handleShorterMonth(originalDate:Date, newDate:Date):Date 
		{
			var result:Date = newDate;
			var originalDayOfMonth:Number = originalDate.getDate();
			
			if (originalDayOfMonth > result.date)
			{
				result = addDays(newDate, -(newDate.date));
			}
			return result;
		}
		
		private static function handleDaylightSavingsTime(originalDate:Date, newDate:Date):Date
		{
			var result:Date = newDate;
			var originalHours:int = originalDate.hours;
			
			if (originalHours != result.hours)
			{
				result=addHours(result, -(result.hours - originalHours));
			}

			var originalMinutes:int = originalDate.minutes;
			
			if (originalMinutes != result.minutes)
			{
				result = addMinutes(result, -(result.minutes - originalMinutes));
			}
			
			var originalOffset:int = originalDate.getTimezoneOffset();
			
			if (originalOffset != result.getTimezoneOffset())
			{
				result = addMinutes(result, -(result.getTimezoneOffset() - originalOffset));
			}		
			
			return result;
		}
		
	}
}